/*
 * SmartCam master processor library
 * Platform independent coprocessor functions.
 */

#include <string.h>
#include <errno.h>
#include <log.h>

#include "sc.h"
#include "globals.h"
#include "scc.h"
#include "scu.h"
#include "management.h"

void scComRemoteBufferSetup(sc_buf_t *b)
{
  scc_msg_t msg;

  lprintf(STREAM(scl.info), "Requesting allocation of stream %d buffer %d on %s",
	  b->stream->id, b->id, b->processor->name);

  memset(&msg, 0, sizeof(scc_msg_t));
  msg.header.source = SCC_MASTER_PROCESSOR;
  msg.header.destination = b->processor->id;
  msg.header.size = sizeof(scc_msg_t)-sizeof(scc_hdr_t);
  msg.header.type = SCC_MSGTYPE_BUFFERCREATE;

  memcpy(msg.data, &b->id, sizeof(int));
  msg.size = b->size;
  sccSendMessage((scc_hdr_t*)&msg);
}

void scComRemoteTransportSetup(sc_buf_t *src, sc_buf_t *dst, int weight)
{
  scc_msg_t msg;
  
  lprintf(STREAM(scl.info), "Requesting transport of stream %d buf %d on %s to buf %d on %s with weight %d",
          src->stream->id, src->id, src->processor->name, dst->id, dst->processor->name, weight);

  memset(&msg, 0, sizeof(scc_msg_t));
  msg.header.source = SCC_MASTER_PROCESSOR;
  msg.header.destination = src->processor->id;
  msg.header.size = sizeof(scc_msg_t)-sizeof(scc_hdr_t);
  msg.header.type = SCC_MSGTYPE_TRANSPORTCREATE;

  memcpy(&msg.data[0], &src->id, sizeof(int));
  msg.processor = dst->processor->id;
  memcpy(&msg.data[sizeof(int)], &dst->id, sizeof(int));
  msg.opid = weight;
  sccSendMessage((scc_hdr_t*)&msg);
}

void scComRemoteBufferFinalize(sc_buf_t *b)
{
  scc_msg_t msg;

  lprintf(STREAM(scl.info), "Requesting finalization of stream %d buffer %d on %s",
	  b->stream->id, b->id, b->processor->name);

  memset(&msg, 0, sizeof(scc_msg_t));
  msg.header.source = SCC_MASTER_PROCESSOR;
  msg.header.destination = b->processor->id;
  msg.header.size = sizeof(scc_msg_t)-sizeof(scc_hdr_t);
  msg.header.type = SCC_MSGTYPE_BUFFERFINALIZE;

  memcpy(msg.data, &b->id, sizeof(int));
  sccSendMessage((scc_hdr_t*)&msg);  
}

void scComRemoteOperationEnqueue(sc_op_t *o)
{
  int i, arguments=0;
  scc_msg_t msg;
  sc_arg_t *a;
  sc_proc_t *p=o->processor;

  lprintf(STREAM(scl.info), "Enqueueing operation %d on %s",
	  o->id, p->name);

  /* Count INPUT and STREAM arguments */
  i=-1;
  while ((i = tblgetnexti(&o->arguments, i)) >= 0)
  {
    tblget(&o->arguments, i, &a);
    if (a->intent == SC_INTENT_IN || a->instance->variable->type == SC_VAR_STREAM)
      arguments++;
  }

  memset(&msg, 0, sizeof(scc_msg_t));
  msg.header.source = SCC_MASTER_PROCESSOR;
  msg.header.destination = p->id;
  msg.header.size = sizeof(scc_msg_t)-sizeof(scc_hdr_t);
  msg.header.type = SCC_MSGTYPE_OPERATIONENQUEUE;

  msg.opid = o->id;
  msg.optype = o->type;
  msg.size = arguments;
  sccSendMessage((scc_hdr_t*)&msg);
}

void scComRemoteArgumentDistribute(sc_arg_t *a)
{
  scc_msg_t msg;
  sc_op_t *o = a->operation;
  sc_proc_t *p = o->processor;
  sc_buf_t *b;
  sc_var_t *v = a->instance->variable;

  lprintf(STREAM(scl.info), "Passing argument %d of operation %d to %s",
	  a->id, o->id, p->name);

  /* Construct and send the message */
  memset(&msg, 0, sizeof(scc_msg_t));
  msg.header.source = SCC_MASTER_PROCESSOR;
  msg.header.destination = p->id;
  msg.header.size = sizeof(scc_msg_t)-sizeof(scc_hdr_t);
  msg.header.type = SCC_MSGTYPE_OPERATIONARGUMENT;

  msg.opid = o->id;
  msg.optype = o->type;
  msg.argid = a->id;
  msg.argintent = a->intent;
  msg.argtype = v->type;

  if (v->type == SC_VAR_STREAM)
  {
    abortOnNULL(STREAM(scl.notice), tblget(&v->buffers, p->id, &b));

    memcpy(msg.data, &b->id, sizeof(int));
  }
  else
  {
    memcpy(msg.data, v->data, v->size);
  }

  sccSendMessage((scc_hdr_t*)&msg);
}
